/**
 * TaskEngineImpl.java
 * com.sitech.dmcs.core.impl
 * Function： TODO 
 *
 *   ver  author   date    
 * ──────────────────────────────────
 *   	 geutopia  Mar 3, 2011        
 *
 * Copyright (c) 2011, TNT All Rights Reserved.
*/

package com.sitech.timing;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.CronExpression;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;

import com.sitech.timing.domain.GroupTaskInfo;
import com.sitech.timing.domain.GroupTaskInstance;
import com.sitech.timing.dao.ParamDao;
import com.sitech.timing.domain.ParamDetail;
import com.sitech.timing.domain.ParamInfo;
import com.sitech.timing.domain.ParamTaskTypeRelation;
import com.sitech.timing.domain.ParamType;
import com.sitech.timing.dao.TaskDao;
import com.sitech.timing.domain.TaskInfo;
import com.sitech.timing.domain.TaskType;
import com.sitech.server.domain.ServerInfo;
import com.sitech.server.service.ServerService;
import com.sitech.timing.GroupTaskContext;
import com.sitech.timing.TaskEngine;
import com.sitech.timing.TaskGroupJob;

/**
 * ClassName:TaskEngineImpl
 * Function: TODO ADD FUNCTION
 * Reason:	 TODO ADD REASON
 *
 * @author   geutopia
 * @version  
 * @since    Ver 1.1
 * @Date	 2011	Mar 3, 2011		3:47:31 PM
 *
 * @see 	 
 */

public class TaskEngineImpl implements TaskEngine
{
	
	private static final Log log = LogFactory.getLog(TaskEngineImpl.class);
	private Scheduler scheduler; 
	private static String JOB_NAME_PERFIX = "BASD_JOB_";
	private static String JOB_GROUP_NAME= "BASD_JOB_GROUP";
	private static String JOB_TRIGGER_NAME_PERFIX= "BASD_JOB_TRIGGER_";
	
	
	private TaskDao taskDao;
	private ParamDao paramDao;
	private ServerService serverService;

	

	public void start()
	{
		log.info("TaskEngine start at " + (new Date()).toString());
		
		 List<GroupTaskInfo> groupTaskList = taskDao.getAllGroupTask();
		 List<TaskInfo> taskList = taskDao.getAllTask();
		 List<TaskType> taskTypeList =  taskDao.getAllTaskType();
		 List<ParamInfo> paramInfoListt = paramDao.getAllParamInfo();
		 List<ParamType> paramTypeList = paramDao.getAllParamType();
		 List<ParamDetail> paramDetailList = paramDao.getAllParamDetail();
		 List<ParamTaskTypeRelation> relationList = paramDao.getAllParamRelation();

		if (groupTaskList != null && groupTaskList.size() > 0 && taskList != null && taskList.size() > 0)
		{
			initTask(groupTaskList,taskList);
			initSubGroupTask(groupTaskList);
			initTaskType(taskList,taskTypeList);
			initTaskParam(taskList,paramInfoListt);
			initParamType(taskTypeList,relationList,paramTypeList);
			initParamDetail(paramTypeList,paramDetailList);
		}

		try
		{
			initializeTaskPool(taskTypeList);
			initializeJob(groupTaskList);
		}
		catch (SchedulerException schedulerException)
		{
			log.error("TaskEngine start error,  Scheduler error", schedulerException);
		}
		catch (ParseException parseException)
		{
			log.error("TaskEngine start error, please check the task CronTrigger", parseException);
		}
		catch (RuntimeException exception)
		{
			log.error("TaskEngine start error", exception);
		}
		log.info("TaskEngine start success " + (new Date()).toString());

	}

	private void initTask(List<GroupTaskInfo> groupTaskList, List<TaskInfo> taskList)
	{
		for (GroupTaskInfo groupTaskInfo : groupTaskList)
		{
			if (taskList != null && taskList.size() > 0)
			{
				for (TaskInfo taskInfo : taskList)
				{
					if (taskInfo != null && groupTaskInfo.getGroupTaskId().equals(taskInfo.getTaskGroupId()))
					{
						if (groupTaskInfo.getTaskInfoList() != null)
						{
							groupTaskInfo.getTaskInfoList().add(taskInfo);
						}
						else
						{
							List<TaskInfo> tempTaskList = new ArrayList<TaskInfo>();
							tempTaskList.add(taskInfo);
							groupTaskInfo.setTaskInfoList(tempTaskList);
						}
					}
				}
			}
			GroupTaskContext.addGroupTaskInfo(groupTaskInfo);
		}
	}

	private void initSubGroupTask(List<GroupTaskInfo> groupTaskList)
	{
		for (GroupTaskInfo groupTaskInfo : groupTaskList)
		{
			if (groupTaskInfo != null)
			{
				String superGroupTaskId = groupTaskInfo.getSuperGroupTaskId();
				if (superGroupTaskId != null && !"".equals(superGroupTaskId) && !"0".equals(superGroupTaskId.trim()))
				{
					GroupTaskInfo superGroupTaskInfo = GroupTaskContext.getGroupTaskInfo(superGroupTaskId);
					if (superGroupTaskInfo != null)
					{
						List<GroupTaskInfo> subList = superGroupTaskInfo.getSubGroupTaskInfoList();
						if (subList == null)
						{
							subList = new ArrayList<GroupTaskInfo>();
						}
						subList.add(groupTaskInfo);
						superGroupTaskInfo.setSubGroupTaskInfoList(subList);
					}
				}

			}
		}
	}

	private void initTaskType(List<TaskInfo> taskList, List<TaskType> taskTypeList)
	{
		for (TaskInfo taskInfo : taskList)
		{
			if (taskInfo != null && taskInfo.getTaskTypeId() != null)
			{
				for (TaskType taskType : taskTypeList)
				{
					if (taskInfo.getTaskTypeId().equals(taskType.getTaskTypeId()))
					{
						taskInfo.setTaskType(taskType);
					}
				}
			}
		}
	}

	private void initTaskParam(List<TaskInfo> taskList, List<ParamInfo> paramInfoList)
	{
		for (ParamInfo paramInfo : paramInfoList)
		{
			String taskId = paramInfo.getTaskId();
			if (taskId != null && !"".equals(taskId))
			{
				for (TaskInfo taskInfo : taskList)
				{
					if (taskId.equals(taskInfo.getTaskInfoId()))
					{
						if (taskInfo.getParamInfoList() == null)
						{
							taskInfo.setParamInfoList(new ArrayList<ParamInfo>());
						}
						taskInfo.getParamInfoList().add(paramInfo);
					}
				}
			}
			GroupTaskContext.addParamInfo(paramInfo);
		}
	}

	private void initParamType(List<TaskType> taskTypeList, List<ParamTaskTypeRelation> relationList,List<ParamType> paramTypeList)
	{
		for (TaskType taskType : taskTypeList)
		{
			for (ParamTaskTypeRelation typeRelation : relationList)
			{
				if (typeRelation.getTaskTypeId().equals(taskType.getTaskTypeId()))
				{
					if (taskType.getParamTaskTypeRelationList() == null)
					{
						taskType.setParamTaskTypeRelationList(new ArrayList<ParamTaskTypeRelation>());
					}
					taskType.getParamTaskTypeRelationList().add(typeRelation);

					for (ParamType paramType : paramTypeList)
					{
						if (paramType.getParamTypeId().equals(typeRelation.getParamTypeId()))
						{
							if (taskType.getParamTypeList() == null)
							{
								taskType.setParamTypeList(new ArrayList<ParamType>());
							}
							taskType.getParamTypeList().add(paramType);
							typeRelation.setParamType(paramType);
						}
					}

				}
			}

		}
	}

	private void initParamDetail(List<ParamType> paramTypeList,List<ParamDetail> paramDetailList)
	{
		for (ParamType paramType : paramTypeList)
		{
			for (ParamDetail paramDetail : paramDetailList)
			{
				if (paramDetail.getParamTypeId().equals(paramType.getParamTypeId()))
				{
					if (paramType.getParamDetailList() == null)
					{
						paramType.setParamDetailList(new ArrayList<ParamDetail>());
					}
					paramType.getParamDetailList().add(paramDetail);
				}
			}
		}
	}

	/**
	 * initializeTaskPool:(这里用一句话描述这个方法的作用) TODO(这里描述这个方法适用条件 – 可选)
	 * TODO(这里描述这个方法的执行流程 – 可选) TODO(这里描述这个方法的使用方法 – 可选) TODO(这里描述这个方法的注意事项 –
	 * 可选)
	 * 
	 * @throws
	 * @since Ver 1.1
	 */

	private void initializeTaskPool(List<TaskType> taskTypeList)
	{
		for (TaskType taskType : taskTypeList)
		{
			if (GroupTaskContext.getThreadPoolExecutor(taskType.getTaskTypeId()) == null)
			{
				LinkedBlockingQueue<Runnable> linkedBlockingQueue = new LinkedBlockingQueue<Runnable>();

				ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(taskType.getMinPoolSize(), taskType
						.getMaxPoolSize(), Integer.valueOf(System
						.getProperty(TimingConst.PROPERTY_TASK_POOL_KEEP_ALIVETIME)), TimeUnit.SECONDS,
						linkedBlockingQueue);
				GroupTaskContext.addThreadPoolExecutor(taskType.getTaskTypeId(), threadPoolExecutor);
			}
		}
	}

	private void initializeJob(List<GroupTaskInfo> groupTaskList) throws SchedulerException, ParseException
	{
		String serverId = getLocalServerId();

		SchedulerFactory sf = new StdSchedulerFactory();
		scheduler = sf.getScheduler();
		
		for (GroupTaskInfo groupTaskInfo : groupTaskList)
		{
			initJob(groupTaskInfo, scheduler, serverId);
		}
		scheduler.start();
	}

	
	private void initJob(GroupTaskInfo groupTaskInfo,Scheduler scheduler,String serverId) throws ParseException, SchedulerException
	{
		if (groupTaskInfo != null
				&& TimingConst.GROUPTASK_RUNTYPE_AUTO.equals(groupTaskInfo.getRunType())
				&& groupTaskInfo.getRunTrigger() != null
				&& !"".equals(groupTaskInfo.getRunTrigger())
				&& (serverId == null || "".equals(serverId) || serverId.equals(groupTaskInfo.getRunServer())
						|| groupTaskInfo.getRunServer() == null || "".equals(groupTaskInfo.getRunServer())))
		{
			if (CronExpression.isValidExpression(groupTaskInfo.getRunTrigger()))
			{
				String jobName = JOB_NAME_PERFIX + groupTaskInfo.getGroupTaskId();
				JobDetail job = new JobDetail(jobName, JOB_GROUP_NAME, TaskGroupJob.class);

				job.getJobDataMap().put(TimingConst.QUARTZ_DATA_MAP_NAME, groupTaskInfo.getGroupTaskId());
				CronTrigger trigger = new CronTrigger( JOB_TRIGGER_NAME_PERFIX + groupTaskInfo.getGroupTaskId(), JOB_GROUP_NAME,
						jobName, JOB_GROUP_NAME, groupTaskInfo.getRunTrigger());
				scheduler.scheduleJob(job, trigger);
			}
		}
	}

	public void refreshAll()
	{
		log.info("TaskEngine Refresh begin...");
		try
		{
			scheduler.shutdown();
			GroupTaskContext.refeshALL();
			log.info("TaskEngine shutdown...");

		}
		catch (SchedulerException schedulerException)
		{
			log.error("TaskEngine scheduler shutdown error.",schedulerException);
		}
		start();
		log.info("TaskEngine Refresh End...");
	}

	public void refresh(String groupTaskId)
	{
		try
		{
			scheduler.deleteJob(JOB_NAME_PERFIX+groupTaskId, JOB_GROUP_NAME);
			
			List<GroupTaskInfo> groupTaskList = new ArrayList<GroupTaskInfo>();
			GroupTaskInfo groupTaskInfo  = taskDao.getGroupTaskInfo(groupTaskId);
			List<GroupTaskInfo> subGoupTaskList = taskDao.getGroupTaskBySuperGroupId(groupTaskId);
			if(subGoupTaskList != null && subGoupTaskList.size() > 0)
			{
				List<GroupTaskInfo> subList = new ArrayList<GroupTaskInfo>();
				for(GroupTaskInfo subGroupTask : subGoupTaskList)
				{
					subList.add(GroupTaskContext.getGroupTaskInfo(subGroupTask.getGroupTaskId()));
				}
				groupTaskInfo.setSubGroupTaskInfoList(subList);

			}
			groupTaskList.add(groupTaskInfo);
			
			List<TaskInfo> taskList = taskDao.getTaskByGroupTaskId(groupTaskId);
			List<TaskType> taskTypeList  = taskDao.getTaskTypeByGroupTaskId(groupTaskId);
			List<ParamInfo> paramInfoList = paramDao.getParamInfoByGroupTaskId(groupTaskId);
			List<ParamTaskTypeRelation> relationList = paramDao.getParamRelationByGroupTaskId(groupTaskId);
			List<ParamType> paramTypeList = paramDao.getParamTypeByGroupTaskId(groupTaskId);
			List<ParamDetail> paramDetailList = paramDao.getParamDetailByGroupTaskId(groupTaskId);
			
			initTask(groupTaskList,taskList);
			initSubGroupTask(groupTaskList);
			initTaskType(taskList,taskTypeList);
			initTaskParam(taskList,paramInfoList);
			initParamType(taskTypeList,relationList,paramTypeList);
			initParamDetail(paramTypeList,paramDetailList);
			
			initializeTaskPool(taskTypeList);
			initJob(groupTaskInfo, scheduler, getLocalServerId());

		}
		catch (SchedulerException e)
		{
			e.printStackTrace();
		}
		catch (ParseException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void refreshTask(String taskId)
	{
		
	}

	private String getLocalServerId()
	{
		ServerInfo localServer = serverService.getLocalServer();
		if (localServer != null)
		{
			return localServer.getServerId();
		}
		else
		{
			return null;
		}
	}
	
	private void loadGroupTaskInstance()
	{
		List<GroupTaskInstance> list = taskDao.getGroupTaskInstanceByStatus(TimingConst.GROUPTASK_STATUS_RUN);

	}
	
	
	public TaskDao getTaskDao()
	{
		return taskDao;
	}

	public void setTaskDao(TaskDao taskDao)
	{
		this.taskDao = taskDao;
	}

	public ParamDao getParamDao()
	{
		return paramDao;
	}

	public void setParamDao(ParamDao paramDao)
	{
		this.paramDao = paramDao;
	}

	public ServerService getServerService()
	{
		return serverService;
	}

	public void setServerService(ServerService serverService)
	{
		this.serverService = serverService;
	}

}
